<?php

namespace App\Jobs;

use App\Models\Game\Center\Apk;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use Madnest\Madzipper\Madzipper;

class MakeApk implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * @var Apk
     */
    public $apk;

    public $basePath;

    public $outputPath;

    private $keyStore;

    private $keyPass;

    private $keyAlias;

    private $apkSigner;

    public function __construct(Apk $apk)
    {
        $this->apk = $apk;
        $this->basePath = config('game.apk.basePath');
        $this->outputPath = config('game.apk.outputPath');
        $this->apkSigner = config('game.apk.apkSigner');
        $this->keyStore = config('game.apk.keyStore');
        $this->keyPass = config('game.apk.keyPass');
        $this->keyAlias = config('game.apk.keyAlias');
    }

    public function handle(Madzipper $zipper)
    {
        if (!file_exists($this->apk->base_path)) {
            info(__METHOD__, ['基础包不存在, 路径: '. $this->apk->base_path]);
            return false;
        }

        // 复制一份基础包
        copy($this->apk->base_path, $this->apk->full_path);

        // 渠道号|平台请求地址|渠道类型
        $configData = [
            $this->apk->source,
            $this->apk->domain_platform,
            $this->apk->appSource->type,
        ];
        $configName = implode('|', $configData);

        try {
            $zipper->zip($this->apk->full_path);
            $zipper->remove('META-INF/');
            $zipper->addEmptyDir('META-INF');
            $zipper->folder('META-INF')->addString('apk.pack', $configName);
            $zipper->close();

            $this->signApk($this->apk->full_path);
        } catch (\Exception $e) {
            info(__METHOD__, [$e->getMessage()]);
            return false;
        }

        // 更新状态
        $this->apk->path = str_replace(Storage::disk('static')->path(''), '', $this->apk->full_path);
        $this->apk->status = Apk::STATUS_MAKED;
        $this->apk->save();
    }

    /**
     * APK签名
     * @param string $apkPath
     * @throws \Exception
     */
    private function signApk(string $apkPath)
    {
        $alignPath = str_replace('.apk', '.align.apk', $apkPath);
        $command = sprintf("zipalign -p -f -v 4 %s %s", $apkPath, $alignPath);
        exec($command, $output, $result_code);
        info([$command, $output, $result_code]);

        // 使用指定 apksigner.jar 进行签名
        $command = sprintf("java -jar %s sign --ks %s --ks-pass pass:%s --ks-key-alias %s --out %s %s", $this->apkSigner, $this->keyStore, $this->keyPass, $this->keyAlias, $apkPath, $alignPath);
        exec($command, $output, $result_code);
        info([$command, $output, $result_code]);
        if ($result_code) {
            info(implode(PHP_EOL, $output));
            throw new \Exception('APK签名失败');
        }
        info(__METHOD__, ['APK签名成功', $apkPath]);

        // 签名成功后删除对齐用的APK
        exec("rm -f {$alignPath}");
    }
}
